package com.otod.tl.generate;

import freemarker.template.Template;

import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer;
import org.springframework.ui.freemarker.FreeMarkerTemplateUtils;

import com.otod.commons.utils.StringUtils;

import java.io.File;
import java.io.FileOutputStream;
import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.ResultSet;
import java.sql.Statement;
import java.util.*;


public class GenerateCode {
	private static String excludFields = ",createOrgNo,createOrg,createEmpNo,createEmp,createIpaddr,createDt,updateOrgNo,updateOrg,updateEmpNo,updateEmp,updateIpaddr,updateDt,isDel,";
	
	public static void main(String[] args) {
		System.out.println("---------start");
		GenerateCode codeGe =new GenerateCode();

		String moduleName = "pm";
		String packageName = "prj";
		String [] tables = {"pm_r_task_emp"};
		String template [] =  {"bean:Vo:java","mapper:Mapper:java","xml:-mapper:xml"};//"bean::java","mapper:Mapper:java","xml:Maper:xml","setMap:Txt:txt"
		
		codeGe.generate(moduleName,packageName,tables,template);
		System.out.println("---------end");
	}
	
	public void generate(String moduleName,String packageName,String [] tables,String template [] ){
		ApplicationContext cxt = new ClassPathXmlApplicationContext("applicationContext.xml");
		SqlSessionFactory sessionFactory = (SqlSessionFactory) cxt.getBean("sqlSessionFactory");
		FreeMarkerConfigurer freeMarkerConfigurer  = (FreeMarkerConfigurer)cxt.getBean("freemarkerConfig");
		try {
			SqlSession session = sessionFactory.openSession();
			Connection conn = session.getConnection();
			DatabaseMetaData metaData = conn.getMetaData();
			
			//获取表
			//	ResultSet rs = metaData.getTables(conn.getCatalog(), null, null, new String[]{"TABLE"});
			//while(rs.next()) {
			
			if(tables==null){
				System.out.println("未传入表名！");
				return;
			}
			
			for (String tableName:tables){
				Map<String, Object> map = new HashMap<String, Object>();
				
			 //  String tableName =  rs.getString("TABLE_NAME");
				Boolean hasBaseData = false;
				
			   List<Map> list = getCommentByTableName(conn,tableName);
			   List<Map> listNoBaseData = new ArrayList<Map>();
			   for (Map tempMap : list) {
				   if(excludFields.contains(","+(String)tempMap.get("fieldName")+",")){
					   hasBaseData = true;
					   continue;
				   }
				   listNoBaseData.add(tempMap);
			   }
			   
			   
			   String beanName =getClassName(tableName);
			   String beanNamePre = beanName.substring(0, beanName.length()-2);
			   map.put("tableName", tableName);
			   map.put("beanName", beanName);
			   map.put("beanNamePre", beanNamePre);
			   map.put("beanShortName", getName(tableName,0,'_',false));
			   map.put("column", list);
			   map.put("columnNoBaseData", listNoBaseData);
			   map.put("hasBaseData", hasBaseData);
               map.put("moduleName",moduleName);
			   map.put("packageName", packageName);
			   
			   if(beanName.length()==0){
				   return;
			   }
			   for(String t :template){
				   String temp [] = t.split(":");
				   String ftlpath = "template/"+temp[0] + ".ftl" ;
				   Template tpl = freeMarkerConfigurer.getConfiguration().getTemplate(ftlpath );
					// 解析模板并替换动态数据，最终username将替换模板文件中的${username}标签。
					String text = FreeMarkerTemplateUtils.processTemplateIntoString(tpl, map);
					
					String filePath = "c:/code/"+packageName+"/"+temp[0]+"/"  ;
					File file= new File(filePath);
					if(!file.exists()){
						file.mkdirs();
					}
					String path = filePath+beanNamePre +temp[1]+"." + temp[2];
					if("xml".equals(temp[2])){
						path =  filePath+ beanNamePre.substring(0,1).toLowerCase()+beanNamePre.substring(1)  +temp[1]+"." + temp[2];
					}
//							
					File fileEn = new File(path);
					if(fileEn.exists()){
						System.out.println("=========>【"+path+"】已存在，未覆盖");
						continue;
					}
					FileOutputStream fos = new FileOutputStream(path);
					 
					fos.write(text.getBytes());
					
					fos.flush(); 
					fos.close(); 
			   }
			}
			
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	/**
	 * 获取表相关信息
	 * @param conn
	 * @param tableName
	 * @return
	 * @throws Exception
	 */
	public List<Map> getCommentByTableName(Connection conn ,String tableName) throws Exception {
       
        Statement stmt = conn.createStatement();
        ResultSet rs = stmt.executeQuery("SELECT * FROM information_schema.columns WHERE table_name ='" + tableName  + "'");
        System.out.println("-------------tableName   " + tableName + "  :----------------------------");
        List list  =new ArrayList();
        while (rs.next()) {
        	Map map = new HashMap();
        	String columnName = rs.getString("column_name");
     	   	String columnType = rs.getString("DATA_TYPE");
     	   	Long datasize = rs.getLong("CHARACTER_MAXIMUM_LENGTH");
     	   	//int digits = rs.getInt("DECIMAL_DIGITS");
     	   	boolean nullable = rs.getBoolean("IS_NULLABLE");  
     	   	String  remarks = rs.getString("COLUMN_COMMENT");
     	   	String defaultStr = rs.getString("COLUMN_DEFAULT");
     		String pri = rs.getString("COLUMN_KEY");
     		
     		
     		map.put("prikey", pri.equals("PRI"));
     	   	map.put("columnName", columnName);
     	   	map.put("fieldName", getFiledName(columnName));
     		map.put("fieldMethod", getFiledMethod(columnName));
     	   	map.put("type", getType(columnType));
     	   	
     	   	map.put("nullable", nullable);
     	   	map.put("length", datasize);
     	   	map.put("remarks", remarks);

            System.out.println(" 列名：" + getFiledName(columnName) + " 类型： " + getType(columnType) + "是否主键：" + pri.equals("PRI"));
     	   	list.add(map);
		}
   
        return list;
	}
	
	public String getClassName(String name){
		int firstSplite =  name.indexOf("_");
		name = name.substring(0,firstSplite)+name.substring(firstSplite+2);	//去除 前缀，如：PM_T_
		return getName(name,0,'_',true)+"Vo";
	}
	
	public String getFiledName(String name){
		return getName(name,3,'_',false);
	}
	
	public String getFiledMethod(String name){
		String field  =getName(name,3,'_',false) ;
		char [] c = field.toCharArray();
		c[0] = Character.toUpperCase(c[0]);
		return new String(c);
	}
	
	//mysql 数据类型转换
	public String  getType(String type ) throws Exception{
		Hashtable<String,String> ht_columnType=new Hashtable<String,String>();
		ht_columnType.put("char","String");
		ht_columnType.put("varchar","String");
		ht_columnType.put("datetime","Date");	
		ht_columnType.put("timestamp","Date");	
		ht_columnType.put("date", "Date");
		ht_columnType.put("int","Integer");	
		ht_columnType.put("bigint","Long");	
		ht_columnType.put("bit","boolean");		
		ht_columnType.put("decimal","Double");
		ht_columnType.put("longtext", "String");
		ht_columnType.put("float", "Float");
		ht_columnType.put("decimal", "java.math.BigDecimal");
		ht_columnType.put("text", "String");
		
		String ret = ht_columnType.get(type.toLowerCase());
		if(StringUtils.isEmpty(ret)){
			throw new Exception("字段类型未添加映射");
		}
		return ret;
	}
	
	/**
	 * 名称格式化
	 * @param name	原name
	 * @param startIndex	从第几个开始取
	 * @param splite		分隔符号
	 * @param flag			是否大写
	 * @return
	 */
	public String getName(String name,int startIndex,char splite,boolean flag){
		name = name.toLowerCase();
		
		char [] oc = name.toCharArray() ;
		
		char [] nc = new char[oc.length];
		int j = 0 ;
		boolean temp =false;
		int i = name.indexOf(splite) !=-1 && flag ? startIndex:0 ;
		for (; i < oc.length; i++) {
			if(oc[i] == splite){
				temp = true ;
				continue ;
			}
			if(temp){
				nc[j] = Character.toUpperCase(oc[i]) ;
			}else{
				nc[j] = oc[i];
			}
			temp =false ;
			j++ ;	
		}
		
		if (flag) {
			nc[0] = Character.toUpperCase(nc[0]) ;
		}
		name = new String(nc);
		return  name.trim();
	}
	
}
